// 
//  SANEControl.cs
//  
//  Author:
//       Christopher Sawyer <christoofar@gmail.com>
//  
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace Mono.SANE
{
	/// <summary>
	/// A class which provides facilities SANE scanning apparatus
	/// </summary>
	public class SANEControl
	{
		private static bool isSANEAvailable = false;
		private static bool isSANEADFAvailable = false;
		private static string saneVersion = "";
		private static string scanADFVersion = "";
		
		private volatile static Dictionary<string, Scanner> scanners =  new Dictionary<string, Scanner>();
				
		#region ctors()
		static SANEControl ()
		{
			try 
			{
				saneVersion = SANELaunch.GetSANEVersion ();
				isSANEAvailable = true;
				
				// see if ADF is also available
				try
				{
					scanADFVersion = SANELaunch.GetADFVersion ();
					isSANEADFAvailable = true;
				} catch {
					scanADFVersion = "Unavailable";
				}
			
			} catch 
			{
				// Sane is not installed or we cannot call it.
				saneVersion = "Unavailable";
			}
		}
		
		private SANEControl ()
		{
		}
		#endregion
		
		#region Properties
		/// <summary>
		/// Determines whether the SANE scanner utilities are available
		/// </summary>
		public static bool IsSANEAvailable
		{
			get { return isSANEAvailable; }
		}
		
		/// <summary>
		/// Determines if scanadf is available
		/// </summary>
		public static bool IsADFAvailable
		{
			get { return isSANEADFAvailable; }
		}
		
		/// <summary>
		/// Returns the version from scanimage
		/// </summary>
		public static string SANEVersion
		{
			get { return saneVersion; }
		}
		
		/// <summary>
		/// Returns the version of scanadf
		/// </summary>
		public static string ScanADFVersion
		{
			get { return scanADFVersion; }
		}
		
		/// <summary>
		/// A list of the installed imaging devices available to SANE
		/// </summary>
		public static Dictionary<string, Scanner> Scanners
		{
			get 
			{
				if (scanners == null || scanners.Count == 0)
				{
					// Poll SANE for what imaging devices we have
					LocateScanners ();
				}
				
				return scanners;
			}
		}
		#endregion
		
		#region Scanner Ops
		private static void LocateScanners ()
		{
			string[] data = SANELaunch.GetScannerList ();
			
			if (scanners == null) 
			{
				scanners = new Dictionary<string, Scanner> ();
			}
			
			foreach (string line in data)
			{
				string[] scannerdata = line.Split ('^');
				Scanner scanner = new Scanner (scannerdata[1], scannerdata[2], scannerdata[3], scannerdata[4]);
				scanners.Add (scannerdata[1], scanner);
			}
			
			Console.WriteLine (data.Length + " scanner(s) found.");
		}
		
		/// <summary>
		/// Updates the internal list of imaging devices with the information available from SANE
		/// </summary>
		public static void RefreshScanners ()
		{
			LocateScanners ();
		}
		
		/// <summary>
		/// Loads an image file and converts it into a cropped Pixbuf for easy use
		/// </summary>
		/// <param name="filename">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="Gdk.Pixbuf"/>
		/// </returns>
		public static Gdk.Pixbuf GetCroppedPixbufFromFile (string filename)
		{
			System.Drawing.Image i = System.Drawing.Image.FromFile (filename);
			i = SANELaunch.Crop (i);
			return SANELaunch.ImageToPixbuf (i);
		}
		
		/// <summary>
		/// Locates and returns a <see cref="Scanner"/> based on a specific SCAN device ID.
		/// </summary>
		/// <param name="deviceID">
		/// A <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// A <see cref="Scanner"/>.
		/// </returns>
		public static Scanner GetScannerByDeviceID (string deviceID)
		{
			if (scanners != null)
			{
				return scanners[deviceID];
			}
			
			throw new ArgumentOutOfRangeException ("The device " + deviceID + " either does not exist, or there " +
				"are no available scanners at this time.");
		}
		#endregion		
		
	}
}
